﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using Kokomo.PeInspector.Reflection.Disassembly;
using Kokomo.Environment;

namespace Kokomo.PeInspector.Reflection
{
	[ViewType(typeof(CodeMetricsView))]
	class CodeMetricsViewModel : NotifierObject
	{
		public CodeMetricsViewModel(
			MethodBase method
			)
		{
			if (method == null) throw new ArgumentNullException("method");

			this.Method = method;
			this._codeMetricViewModels = new Lazy<IEnumerable<CodeMetricViewModel>>(this.CreateCodeMetricViewModels);
		}

		public MethodBase Method { get; private set; }

		private Lazy<IEnumerable<CodeMetricViewModel>> _codeMetricViewModels;
		public IEnumerable<CodeMetricViewModel> CodeMetricViewModels
		{
			get { return this._codeMetricViewModels.Value; }
		}
		protected IEnumerable<MsilDependencyViewModel> CreateMsilDependencyViewModels()
		{
			List<MsilDependencyViewModel> dependencyViewModels = new List<MsilDependencyViewModel>();

			IEnumerable<MsilDependency> dependencyList = MsilDecompiler.GetDependenciesOf(this.Method);
			if (dependencyList != null)
			{
				foreach (var dependency in dependencyList)
				{
					MsilTypeDependency typeDependency = dependency as MsilTypeDependency;
					MsilMethodDependency methodDependency = dependency as MsilMethodDependency;
					MsilStringDependency stringDependency = dependency as MsilStringDependency;

					MsilDependencyViewModel dependencyViewModel = null;
					if (typeDependency != null)
					{
						dependencyViewModel = new MsilDependencyViewModel(dependency.Offset, typeDependency.GetTypeDependency(), typeDependency.Usage.ToString());
					}
					else if (methodDependency != null)
					{
						dependencyViewModel = new MsilDependencyViewModel(dependency.Offset, methodDependency.GetMethodDependency(), methodDependency.Usage.ToString());
					}
					else if (stringDependency != null)
					{
						dependencyViewModel = new MsilDependencyViewModel(dependency.Offset, string.Format("\"{0}\"", CSharpDocumentBuilder.EscapeString(stringDependency.GetString())));
					}

					if (dependencyViewModel != null)
					{
						dependencyViewModels.Add(dependencyViewModel);
					}
				}
			}

			return dependencyViewModels;
		}
		private IEnumerable<CodeMetricViewModel> CreateCodeMetricViewModels()
		{
			MethodDecompilation disassembly = null;
			try
			{
				disassembly = MsilDecompiler.Decompile(this.Method);
			}
			catch { }
			if (disassembly == null) return null;

			List<CodeMetricViewModel> viewModels = new List<CodeMetricViewModel>(disassembly.Metrics.Count);
			foreach (var metricEntry in disassembly.Metrics)
			{
				CodeMetricViewModel viewModel = new CodeMetricViewModel(metricEntry.Key, metricEntry.Value);
				viewModels.Add(viewModel);
			}

			return viewModels;
		}
	}
}
